home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-11-21 | 8.4 KB | 278 lines | [TEXT/MPS ] |
- (*
- TCPRecvMsg(connectionID,waitTime,OKChar,limit) -- Return a message, where a message is
- defined as either a line starting with the OKChar (if the first line does not start with this,
- then the first line is returned surrounded by "•••"; this is an error indication), which should
- be stripped from the message, followed by lines of text until a period on a line be itself is reached,
- which final line is also stipped; or if OKChar is empty, then no initial line, but just lines of text
- until a period on a line by itself, which is stripped. In addition, the following editing is performed on
- the incoming text: linefeeds are removed; control-Hs and the characters immediately preceeding them
- are removed; ".." at the start of lines is changed is "."; tabs are converted to spaces. If waitTime
- ticks go by without reading a whole message, then return "••• time out •••". If limit characters
- are input without reading a whole message, then "••• message too big •••" is appended
- to the truncated message (but it's all read anyway). This routine should be able to read
- SMTP, NNTP, and POP messages.
-
- To compile and link this file using Macintosh Programmer's Workshop,
-
- pascal -w TCPRecvMsg.p
- link -m ENTRYPOINT -o HyperCommands -rt XFCN=7867 -sn Main=TCPRecvMsg ∂
- TCPRecvMsg.p.o "{Libraries}HyperXLib.o" "{MPW}"Libraries:interface.o
-
- © Copyright 1989 by Apple Computer, Inc.
-
- Initial coding 1/89 by Harry R. Chesley.
- Added empty OKChar processing 4/3/89, Harry R. Chesley.
- *)
-
- {$R-}
-
- {$S TCPRecvMsg } { Segment name must be the same as the command name. }
-
- unit DummyUnit;
-
- interface
-
- uses MemTypes, QuickDraw, OSIntf, ToolIntf, HyperXCmd;
-
- procedure EntryPoint(paramPtr: XCmdPtr);
-
- implementation
-
- const
-
- LINEFEED = 10; { ASCII for line feed. }
- RETURN = 13; { ASCII for carriage return. }
- CONTROLH = 8; { ASCII for backspace. }
- TAB = 9; { ASCII for tab. }
- FORMFEED = 12; { ASCII for form feed. }
- TABSTOPS = 8; { Number of columns per tab stop. }
-
- procedure TCPRecvMsg(paramPtr: XCmdPtr); forward;
-
- procedure EntryPoint(paramPtr: XCmdPtr);
-
- begin
- TCPRecvMsg(paramPtr);
- end;
-
- procedure TCPRecvMsg(paramPtr: XCmdPtr);
-
- type stateList =
- (firstChar,lastErrorLinefeed,secondWord,endOfOKLine,endOfLine,firstPeriod,
- secondPeriod,lastLinefeed);
-
- var str: Str255;
- l: longInt;
- i: integer;
- waitForChars: longInt; { Ticks to wait until for characters (compated to TickCount). }
- resultHand: Handle; { A handle to the result string. }
- resultSize: longInt; { The size of the result string (minus the zero termination tacked on last). }
- limit: longInt; { Size limitation. }
- okChar: SignedByte; { Message is OK if first char is this. }
- theChar: SignedByte; { Input character. }
- tabColumn: integer; { Current column. }
-
- procedure Fail(errMsg: Str255); { set theResult and quit }
- begin
- paramPtr^.returnValue := PasToZero(paramPtr,errMsg);
- exit(TCPRecvMsg);
- end;
-
- {$I TCPUtil.inc}
-
- procedure disposAndFail(err: str255);
- { Fail routine used after the result handle has been allocated. }
-
- begin
- DisposHandle(resultHand);
- Fail(err);
- end;
-
- procedure putByte(b: SignedByte);
- { Put the byte b after the output handle, increasing the handle's size in the process. }
-
- var p: Ptr;
-
- begin
- if resultSize < limit then
- begin
- resultSize := resultSize+1;
- SetHandleSize(resultHand,resultSize);
- if MemError <> noErr then disposAndFail('§§§ SetHandleSize failed §§§');
- p := Ptr(ord4(resultHand^)+resultSize-1);
- p^ := b;
- end;
- end;
-
- procedure putString(s: Str255);
- { Put each byte in the string. }
-
- var i: integer;
-
- begin
- for i := 1 to length(s) do
- putByte(SignedByte(s[i]));
- end;
-
- function nextByte: SignedByte;
- { Return the next byte in the buffer, reading more in if necessary. }
-
- var waitUntil: longInt;
- readIn: longInt;
-
- begin
- with Connection^ do
- begin
- if incomingSize = 0 then
- begin
- waitUntil := TickCount + waitForChars;
- while true do
- begin
- { Check the status. }
- ZeroIOParms;
- SyncControlBlock.csCode := TCPcsStatus;
- if PBControl(@SyncControlBlock,false) <> noErr then
- disposAndFail('§§§ TCP status failed §§§');
- readIn := ControlWordAtOffset(60);
- { If there's something to read, do so. }
- if readIn > 0 then
- begin
- { Read only up to the buffer size. }
- if readIn > INCOMINGBUFSIZE then readIn := INCOMINGBUFSIZE;
- { Issue the read. }
- ZeroIOParms;
- SyncControlBlock.csCode := TCPcsRcv;
- PutControlLongAtOffset(ord4(@inBuf),36);
- PutControlWordAtOffset(readIn,40);
- if PBControl(@SyncControlBlock,false) <> noErr then
- disposAndFail('§§§ TCP read failed §§§');
- incomingSize := readIn;
- incomingPtr := @inBuf;
- leave;
- end
- { If not, check the timeout condition. }
- else if TickCount > waitUntil then
- begin
- putByte(0);
- paramPtr^.returnValue := resultHand;
- exit(TCPRecvMsg);
- end;
- end;
- end;
- { Get the byte. }
- nextByte := incomingPtr^;
- incomingPtr := Ptr(ord4(incomingPtr)+1);
- incomingSize := incomingSize-1;
- end;
- end;
-
- begin
- if paramPtr^.paramCount <> 4 then Fail('§§§ parameter count is not 4 §§§');
-
- SetUpConnectionID;
-
- waitForChars := GetLongParm(2); { Second parameter is whether to wait. }
- GetStrParm(3,str); { Third parameter is OK char. }
- if length(str) = 0 then okChar := 0
- else okChar := SignedByte(str[1]);
- limit := GetLongParm(4); { Fourth parameter is the size limit. }
-
- { Create the return handle. }
- resultHand := NewHandle(0);
- resultSize := 0;
-
- { Start in the first column. }
- tabColumn := 0;
-
- { Get the first character. }
- if okChar <> 0 then theChar := nextByte;
- { Check if this is a good message or an error. }
- if (theChar <> okChar) and (okChar <> 0) then
- begin
- { If error, return the line, surounded by bullets. }
- putString('••• ');
- while theChar <> RETURN do
- begin
- putByte(theChar);
- theChar := nextByte;
- end;
- putString(' •••');
- { Skip the linefeed. }
- theChar := nextByte;
- end
- else
- begin
- { Skip the first line. }
- if okChar <> 0 then repeat until nextByte = LINEFEED;
-
- { Repeat for each line. }
- while true do
- begin
- { Check the first char for period. }
- theChar := nextByte;
- if theChar = ord('.') then
- begin
- { Initial period. Might be end-of-message. Check the second char. }
- theChar := nextByte;
- if theChar = RETURN then
- begin
- { End-of-message. Skip the linefeed and return. }
- theChar := nextByte;
- leave;
- end
- { Otherwise, output the initial period. }
- else putByte(ord('.'));
- { Plus the next char if it wasn't a doubled initial period. }
- if theChar <> ord('.') then putByte(theChar);
- { Get the next char in the line. }
- theChar := nextByte;
- end;
- { Do the rest of the line. }
- while theChar <> LINEFEED do
- begin
- if theChar = TAB then
- begin
- { Space out to the tab stop. }
- repeat
- putByte(SignedByte(' '));
- tabColumn := tabColumn+1;
- until (tabColumn mod TABSTOPS) = 0;
- end
- else if theChar = CONTROLH then
- begin
- { Back up one, if there's anything to back up over. }
- if (tabColumn > 0) and (resultSize > 0) then
- begin
- resultSize := resultSize-1;
- tabColumn := tabColumn-1;
- end;
- end
- else if theChar = FORMFEED then
- begin
- { Insert a page-break. }
- for i := 1 to 20 do putByte(SignedByte('◊'));
- for i := 1 to 24 do putByte(RETURN);
- end
- else if theChar <> LINEFEED then
- begin
- { Just put the character out straight, and adjust the tabbing. }
- putByte(theChar);
- if theChar = RETURN then tabColumn := 0
- else tabColumn := tabColumn+1;
- end;
- theChar := nextByte;
- end;
- end;
- { Check if we overrun the allowed size. }
- if resultSize = limit then putString('••• message too big •••');
- end;
-
- { Add in the zero termination for the string. }
- putByte(0);
-
- { Return the handle. }
- paramPtr^.returnValue := resultHand;
- end;
-
- end.
-